package com.bes.bessdk.service.customerdial;


import static com.bes.bessdk.service.customerdial.CustomerDialConstants.CUSTOMER_DIAL_CROP_PHOTO_FORM_KEY;
import static com.bes.bessdk.service.customerdial.CustomerDialConstants.CUSTOMER_DIAL_CROP_PHOTO_LENGTH_KEY;
import static com.bes.bessdk.service.customerdial.CustomerDialConstants.CUSTOMER_DIAL_CROP_PHOTO_WIDTH_KEY;
import static com.bes.bessdk.service.customerdial.CustomerDialConstants.CUSTOMER_DIAL_GET_FLASH_ADDRESS_RESULT;
import static com.bes.bessdk.service.customerdial.CustomerDialConstants.CUSTOMER_DIAL_GET_FLASH_ADDRESS_RESULT_FAIL;
import static com.bes.bessdk.service.customerdial.CustomerDialConstants.CUSTOMER_DIAL_GET_MTU;
import static com.bes.bessdk.service.customerdial.CustomerDialConstants.CUSTOMER_DIAL_GET_SCREEN_PARAMETER;
import static com.bes.bessdk.service.customerdial.CustomerDialConstants.CUSTOMER_DIAL_RECEIVE_ALL_ACK;
import static com.bes.bessdk.service.customerdial.CustomerDialConstants.CUSTOMER_DIAL_RECEIVE_ACK_RESULT;
import static com.bes.bessdk.service.customerdial.CustomerDialConstants.CUSTOMER_DIAL_RECEIVE_DATA_ERROR;
import static com.bes.bessdk.service.customerdial.CustomerDialConstants.CUSTOMER_DIAL_RECEIVE_LSAT_FLASH_ADDR;
import static com.bes.bessdk.service.customerdial.CustomerDialConstants.CUSTOMER_DIAL_SEND_DATA_OVER;
import static com.bes.bessdk.service.customerdial.CustomerDialConstants.CUSTOMER_DIAL_USE_TEST;
import static com.bes.bessdk.service.customerdial.CustomerDialConstants.OP_TOTA_CONFIRM_DATA_ERROR;
import static com.bes.bessdk.service.customerdial.CustomerDialConstants.OP_TOTA_EXCHANGE_MTU_CMD;
import static com.bes.bessdk.service.customerdial.CustomerDialConstants.OP_TOTA_FLASH_ADDRESS_CMD;
import static com.bes.bessdk.service.customerdial.CustomerDialConstants.OP_TOTA_GET_FLASH_ADDRESS_CMD;
import static com.bes.bessdk.service.customerdial.CustomerDialConstants.OP_TOTA_GET_SCREEN_PARAMETER_ACK;
import static com.bes.bessdk.service.customerdial.CustomerDialConstants.OP_TOTA_GET_SCREEN_PARAMETER_CMD;
import static com.bes.bessdk.service.customerdial.CustomerDialConstants.OP_TOTA_LAST_FLASH_ADDR;
import static com.bes.bessdk.service.customerdial.CustomerDialConstants.OP_TOTA_RECEIVE_DATA_ACK;
import static com.bes.bessdk.service.customerdial.CustomerDialConstants.OP_TOTA_RECEIVE_DATA_ERROR;
import static com.bes.bessdk.service.customerdial.CustomerDialConstants.OP_TOTA_WRITE_FLASH_DATA_CMD;
import static com.bes.bessdk.service.customerdial.CustomerDialConstants.OP_TOTA_WRITE_FLASH_WHOLE_CHECK;
import static com.bes.bessdk.service.customerdial.CustomerDialConstants.OP_TOTA_WRITE_FLASH_WHOLE_CHECK_RESULT;
import static com.bes.bessdk.service.customerdial.CustomerDialConstants.OP_TOTA_WRITE_FLASH_WHOLE_CHECK_RESULT_FAIL;
import static com.bes.bessdk.service.customerdial.CustomerDialConstants.OP_TOTA_WRITE_FLASH_WHOLE_CHECK_RESULT_OK;

import android.content.Context;
import android.util.Log;

import com.bes.bessdk.utils.ArrayUtil;
import com.bes.bessdk.utils.CmdInfo;
import com.bes.bessdk.utils.LogUtils;
import com.bes.bessdk.utils.SPHelper;
import com.bes.sdk.core.OtaLog;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

public class CustomerDialCMD {

    static int curMtu = 640 - 16;//根据协议mMtu必须是16的倍数
    static int packagelength = 4 * 1024;
    static int curFlashAddress = 0;
    static byte[] oldDataSource = null;

    static byte[] dataSource = null;
    static byte[][][] dataListSource = null;
    static int packageCount = 0;
    static boolean isDiffUpgrade = false;
    static int sendPackageCount = 0;
    static int receiveAckCount = 0;
    static boolean dataTransferOver = false;
    //    static boolean shouldResonseReceiveDataError = true;
    static List<Integer> flashAddressList_receive = new ArrayList<>();
    static List<Integer> flashAddressList_init = new ArrayList<>();

    static int curFileType = 0;

    static byte[] curGetFlashAddrData = null;

    static byte[] curCmdGetAddress = new CmdInfo(OP_TOTA_FLASH_ADDRESS_CMD, new byte[0]).toBytes();
    static byte[] curCmdAck = new CmdInfo(OP_TOTA_RECEIVE_DATA_ACK, new byte[0]).toBytes();
    static byte[] curReceiveDataAck = new CmdInfo(OP_TOTA_WRITE_FLASH_DATA_CMD, new byte[0]).toBytes();
    static byte[] curCmdCheck = new CmdInfo(OP_TOTA_WRITE_FLASH_WHOLE_CHECK_RESULT, new byte[0]).toBytes();
    static byte[] curScreenParameterAck = new CmdInfo(OP_TOTA_GET_SCREEN_PARAMETER_ACK, new byte[0]).toBytes();
    static byte[] curMtuAck = new CmdInfo(OP_TOTA_EXCHANGE_MTU_CMD, new byte[0]).toBytes();
    static byte[] curReceiveDataErrorAck = new CmdInfo(OP_TOTA_RECEIVE_DATA_ERROR, new byte[0]).toBytes();
    static byte[] curReceiveLastFlashAddr = new CmdInfo(OP_TOTA_LAST_FLASH_ADDR, new byte[0]).toBytes();

    public static byte[] getCurrentScreenParameterCmd() {
        CmdInfo curCmd = new CmdInfo(OP_TOTA_GET_SCREEN_PARAMETER_CMD, new byte[0]);
        return curCmd.toBytes();
    }

    public static byte[] getCurrentMtuCmd() {
        CmdInfo curCmd = new CmdInfo(OP_TOTA_EXCHANGE_MTU_CMD, new byte[0]);
        return curCmd.toBytes();
    }

    public static byte[] getCurGetFlashAddrData() {
        return curGetFlashAddrData;
    }

    public static byte[] getStartTransferCmd(byte[] oldData, byte[] data, int type, int isIncremental, byte[] param) {
        if (type == 1) {
            Date date = new Date(System.currentTimeMillis());
            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd-hh-mm-ss");
            String dateStr = format.format(date);
            String[] dateStrs = dateStr.split("-");
            Log.i("TAG", "getStartTransferCmd: ------" + dateStr);
            param = new byte[7];
            param[0] = ArrayUtil.intToBytesLittle(Integer.valueOf(dateStrs[0]))[0];
            param[1] = ArrayUtil.intToBytesLittle(Integer.valueOf(dateStrs[0]))[1];
            param[2] = (byte) (int)Integer.valueOf(dateStrs[1]);
            param[3] = (byte) (int)Integer.valueOf(dateStrs[2]);
            param[4] = (byte) (int)Integer.valueOf(dateStrs[3]);
            param[5] = (byte) (int)Integer.valueOf(dateStrs[4]);
            param[6] = (byte) (int)Integer.valueOf(dateStrs[5]);
        }
        sendPackageCount = 0;
        isDiffUpgrade = false;
        dataTransferOver = false;
        dataSource = data;
        curFileType = type;
        receiveAckCount = 0;
//        shouldResonseReceiveDataError = true;
//        //testaa
        if (CUSTOMER_DIAL_USE_TEST) {
            initDataListSource();
        }

        CmdInfo curCmd = new CmdInfo(OP_TOTA_GET_FLASH_ADDRESS_CMD, ArrayUtil.bytesSplic(new byte[]{(byte) type}, new byte[]{(byte) isIncremental}, ArrayUtil.intToBytesLittle(data.length), param));
        curGetFlashAddrData = curCmd.toBytes();

        return getCurrentMtuCmd();
    }

    public static void initDataListSource() {
        byte[] data = dataSource;
        packageCount = data.length / packagelength == 0 ? data.length / packagelength : (data.length / packagelength + 1);
        LOG("initDataListSource", "packageCount---" + packageCount);
        LOG("initDataListSource", "dataSource---" + dataSource.length);
        flashAddressList_init = new ArrayList<>();
        flashAddressList_receive = new ArrayList<>();
        dataListSource = new byte[packageCount][][];
        for (int i = 0; i < packageCount; i ++) {
            int packageL = ((i + 1) * packagelength) > data.length ? (data.length - i * packagelength) : packagelength;
            byte[] packageData = new byte[packageL];
            System.arraycopy(data, i * packagelength, packageData, 0, packageL);
            byte[] address = ArrayUtil.int2byte(curFlashAddress);
            flashAddressList_init.add(curFlashAddress);
            flashAddressList_receive.add(0);
            curFlashAddress += packageL;
            byte[] dataCrc = new byte[4];
            byte[] dataLength = new byte[2];
            long crc32 = ArrayUtil.crc32(packageData, 0, packageData.length);
            dataCrc = new byte[]{(byte) crc32, (byte) (crc32 >> 8), (byte) (crc32 >> 16), (byte) (crc32 >> 24)};
            dataLength = new byte[]{ArrayUtil.intToBytesLittle(packageL)[0], ArrayUtil.intToBytesLittle(packageL)[1]};
            CmdInfo curCmd = new CmdInfo(OP_TOTA_WRITE_FLASH_DATA_CMD, ArrayUtil.bytesSplic(address, dataCrc, dataLength, packageData));
            byte [] curData = curCmd.toBytes();
            int count = curData.length / curMtu == 0 ? curData.length / curMtu : (curData.length / curMtu + 1);
            if (count == 0) {
                count = 1;
            }
            dataListSource[i] = new byte[count][];
            for (int j = 0; j < count; j ++) {
                int l = ((j + 1) * curMtu) > curData.length ? (curData.length - j * curMtu) : curMtu;
                byte[] d = new byte[l];
                System.arraycopy(curData, j * curMtu, d, 0, l);
                dataListSource[i][j] = d;
            }
        }
        LOG("initDataListSource", "flashAddressList_init---" + flashAddressList_init.size());

//        Log.i("TAG", "dataListSource: ------" + dataListSource.length);
//        for (int i = 0; i< dataListSource.length; i ++) {
//            byte[][] aa = dataListSource[i];
//            Log.i("TAG", "aa: ------" + aa.length);
//            for (int j = 0; j < aa.length; j ++) {
//                byte[] bb = aa[j];
//                Log.i("TAG", "bb: ------" + ArrayUtil.toHex(bb));
//                Log.i("TAG", "bb: ------" + bb.length);
//            }
//
//        }
    }

    public static byte[][] getSendPackageData() {
        int index = flashAddressList_receive.indexOf(0);
        LOG("CustomerDialCMD", "getSendPackageData: index0------>"  + index);

        if (index == -1) {
            index = flashAddressList_receive.indexOf(1);
            LOG("CustomerDialCMD", "getSendPackageData: index1------>"  + index);
            if (index == -1) {
                //over

                return new byte[][]{};
            } else {
                int index1 = flashAddressList_receive.indexOf(1);
                LOG("CustomerDialCMD", "getSendPackageData: index2------>"  + index);
                while (index1 != -1) {
                    flashAddressList_receive.remove(index1);
                    flashAddressList_receive.add(index1, 0);
                    index1 = flashAddressList_receive.indexOf(1);
                }
                return dataListSource[flashAddressList_receive.indexOf(0)];
            }
        } else {
            flashAddressList_receive.remove(index);
            flashAddressList_receive.add(index, 1);
            return dataListSource[index];
        }
    }

    public static byte[] getWholeDataCheckCmd() {
        dataTransferOver = true;
        CmdInfo curCmd = new CmdInfo(OP_TOTA_WRITE_FLASH_WHOLE_CHECK, new byte[]{(byte) curFileType});
        return curCmd.toBytes();
    }

    public static byte[] getConfirmDataErrorCmd() {
        CmdInfo curCmd = new CmdInfo(OP_TOTA_CONFIRM_DATA_ERROR, new byte[0]);
        return curCmd.toBytes();
    }

    public static int receiveData(byte[] data, Context context) {
        LOG("CustomerDialCMD", "receiveData: ------"  + ArrayUtil.toHex(data));
        if (ArrayUtil.startsWith(data, new byte[]{curCmdGetAddress[0], curCmdGetAddress[1]})) {
            LOG("CustomerDialCMD", "receiveData: --------读取地址");

            byte[] flashAddress = new byte[4];
            System.arraycopy(data, curCmdGetAddress.length, flashAddress, 0, flashAddress.length);
            curFlashAddress = ArrayUtil.bytesToIntLittle(flashAddress);
            LOG("CustomerDialCMD", "curFlashAddress---" + curFlashAddress);
            if (curFlashAddress == 0) {
                return CUSTOMER_DIAL_GET_FLASH_ADDRESS_RESULT_FAIL;
            }
            initDataListSource();
            return CUSTOMER_DIAL_GET_FLASH_ADDRESS_RESULT;
        } else if (ArrayUtil.startsWith(data, new byte[]{curCmdAck[0], curCmdAck[1]})) {
            byte[] cmdBytes = new byte[2];
            System.arraycopy(data, curCmdAck.length, cmdBytes, 0, cmdBytes.length);
            if (ArrayUtil.startsWith(cmdBytes, new byte[]{curReceiveDataAck[0], curReceiveDataAck[1]})) {
                receiveAckCount ++;
                LOG("CustomerDialCMD", "receive ack receiveAckCount---" + receiveAckCount);
                byte[] flashBytes = new byte[4];
                System.arraycopy(data, curCmdAck.length + cmdBytes.length + 4, flashBytes, 0, flashBytes.length);
                int curFAddr = ArrayUtil.bytesToIntLittle(flashBytes);
                LOG("CustomerDialCMD", "receive ack curFAddr---" + curFAddr);
                if (curFAddr == 0) {
                    return 0;
                }
                int curIndex = flashAddressList_init.indexOf(curFAddr);
                LOG("CustomerDialCMD", "receive ack curIndex---" + curIndex);
                if (curIndex > -1) {
                    flashAddressList_receive.remove(curIndex);
                    flashAddressList_receive.add(curIndex, curFAddr);
                } else {
                    LOG("CustomerDialCMD", "receive ack curIndex---error");
                }
                if (sendPackageCount > 1) {
                    sendPackageCount --;
                    return CUSTOMER_DIAL_RECEIVE_ACK_RESULT;
                }
                synchronized (new Object()) {
                    sendPackageCount --;
                }
            }
//            if (shouldResonseReceiveDataError == false) {
//               return 0;
//            }
//            byte[] cmdBytes = new byte[4];
//            System.arraycopy(data, curCmdAck.length, cmdBytes, 0, cmdBytes.length);
//            if (ArrayUtil.startsWith(cmdBytes, new byte[]{curReceiveDataAck[0], curReceiveDataAck[1]})) {
//                receiveAckCount ++;
//                LOG("CustomerDialCMD", "receiveAckCount---" + receiveAckCount);
//                if (receiveAckCount * packagelength >= dataSource.length) {
//                    if (dataTransferOver) {
//                        return 0;
//                    }
//                    return CUSTOMER_DIAL_RECEIVE_ALL_ACK;
//                } else if (curSendPackageCount * packagelength >= dataSource.length) {
//
//                    return CUSTOMER_DIAL_SEND_DATA_OVER;
//                }
//                LOG("CustomerDialCMD", "receiveData sendPackageCount11: ------"  + sendPackageCount);
//                if (sendPackageCount > 1) {
//                    sendPackageCount --;
//                    return CUSTOMER_DIAL_RECEIVE_ACK_RESULT;
//                }
//                synchronized (new Object()) {
//                    sendPackageCount --;
//                }
//                LOG("CustomerDialCMD", "receiveData sendPackageCount22: ------"  + sendPackageCount);
//            } else if (ArrayUtil.startsWith(cmdBytes, new byte[]{curReceiveDataErrorAck[0], curReceiveDataErrorAck[1]})) {
//                LOG("CustomerDialCMD", "CUSTOMER_DIAL_RECEIVE_DATA_ERROR---" + shouldResonseReceiveDataError + "----receiveAckCount---" + receiveAckCount);
//                if (shouldResonseReceiveDataError) {
//                    shouldResonseReceiveDataError = false;
//                    return CUSTOMER_DIAL_RECEIVE_DATA_ERROR;
//                }
//            }
        } else if (ArrayUtil.startsWith(data, new byte[]{curCmdCheck[0], curCmdCheck[1]})) {
            byte type = data[5];
            if (type == (byte) 0x00) {
                receiveAckCount = 0;
                return OP_TOTA_WRITE_FLASH_WHOLE_CHECK_RESULT_OK;
            }
            return OP_TOTA_WRITE_FLASH_WHOLE_CHECK_RESULT_FAIL;
        } else if (ArrayUtil.startsWith(data, new byte[]{curScreenParameterAck[0], curScreenParameterAck[1]})) {
            int dialForm = data[curScreenParameterAck.length];
            byte[] dialWBytes = new byte[2];
            System.arraycopy(data, curScreenParameterAck.length + 1, dialWBytes, 0, dialWBytes.length);
            byte[] dialHBytes = new byte[2];
            System.arraycopy(data, curScreenParameterAck.length + 1 + dialWBytes.length, dialHBytes, 0, dialHBytes.length);
            int dialWidth = ArrayUtil.byte2int(dialWBytes);
            int dialHight = ArrayUtil.byte2int(dialHBytes);
            LOG("CustomerDialCMD", "dialForm: --------" + dialForm);
            LOG("CustomerDialCMD", "dialWidth: --------" + dialWidth);
            LOG("CustomerDialCMD", "dialHight: --------" + dialHight);
            SPHelper.putPreference(context, CUSTOMER_DIAL_CROP_PHOTO_FORM_KEY, dialForm);
            SPHelper.putPreference(context, CUSTOMER_DIAL_CROP_PHOTO_LENGTH_KEY, dialHight);
            SPHelper.putPreference(context, CUSTOMER_DIAL_CROP_PHOTO_WIDTH_KEY, dialWidth);
            return CUSTOMER_DIAL_GET_SCREEN_PARAMETER;
        } else if (ArrayUtil.startsWith(data, new byte[]{curMtuAck[0], curMtuAck[1]})) {
            byte[] mtuBytes = new byte[2];
            System.arraycopy(data, curMtuAck.length, mtuBytes, 0, mtuBytes.length);
            curMtu = ArrayUtil.byte2int(mtuBytes);
            curMtu = curMtu / 16 * 16 - 16;
            LOG("TAG", "curMtu: -----" + curMtu);
            return CUSTOMER_DIAL_GET_MTU;
        }
        return 0;
    }

    public static int getCurMtu() {
        return curMtu;
    }

    public static void resetSendPackageCount() {
        sendPackageCount = 0;
    }

    public static int resetAndCanSend() {
        synchronized (new Object()) {
            sendPackageCount++;
        }
        LOG("CustomerDialCMD", "resetAndCanSend: ------"  + sendPackageCount);

        if (sendPackageCount > 1) {
            return 1;
        }
        return 0;
    }
    public static String getCurProgress() {
        if (dataListSource == null)
            return "";
        int total = dataSource.length;
        if (total == 0) {
            return "0.00";
        }
        double v1 = receiveAckCount * packagelength * 100;
        if (v1 / 100 > total) {
            v1 = total * 100;
        }
        return ArrayUtil.div(v1, total, 2) + "";
    }

    private static void LOG(String TAG, String msg) {
        if (OtaLog.isWriteLog) {
            Log.i(TAG, msg);
        }
        if (!OtaLog.isWriteFile) {
            return;
        }
        LogUtils.writeLog(TAG, msg);
    }
}
